#include<iostream>
#include<string>
#include<time.h>
using std::string;
using namespace std;
extern int round;//总回合数
extern int now_round;//当前回合数
extern Event* event_queue[20];//进入生效队列的事件全局事件


/*
功能：
	结构体Point用来记录当前光标的x,y坐标
*/
struct Point {
	int x, y;
};


/*
功能：
   记录玩家信息
*/
struct Player {
	int player_id;//玩家编号
	std::string name;//玩家名
	int character_id;//使用角色id
	int mp_locat;//记录玩家位置
	int star_num;//记录玩家拥有的星星数
	int step;//记录玩家走过的步数
	Loot* loots[20];//记录玩家所有拥有的道具
	Event* event_queue[20];//进入生效队列的事件
	Loot* loot_queue[20];//进入生效队列的道具
}player[10];//所有玩家的集合


/*
功能：
	储存角色信息
	实现投点功能
	输出背景故事
*/
class Character {
public:
	int id;//角色编号
	std::string character_name;//角色名
	std::string backstory;//背景故事描述
	int dice[10];//骰子花色
	bool choose;//角色是否被选中
	//模拟投点 返回值为点数
	int Roll();
	//输出背景故事
	void PrintBackstory();
};

Character character[20];//所有角色的集合 下标和id相同

/*
功能：
	记录地图位置 编号 事件
*/
class Map {
public:
	Point a, b;//记录地图块位置 其中a为x,y偏小的那个坐标 b为x,y偏大的那个坐标
	int map_id;//记录地图块编号
	Event* event_id;//指向设置的事件
	bool star;//记录是否存在星星 true为存在false为不存在
	bool crossing;//记录是否是岔路 true为是false为不是
};

Map mp[200];//所有地图块的集合


/*
功能：
	记录事件编号
	确定当前回合事件是否生效
	实现事件逻辑
*/
class Event {
public:
	int event_time;//记录事件生效时间 1：立即生效 2：回合开始时生效
	int event_id;//记录事件编号
	std::string event_name;//记录事件名
	/*
	功能：
		实现事件逻辑
	参数：
		触发的玩家id
	返回值：
		无
	*/
	virtual void EventFun(int x);
	/*
	功能：
		确定当前回合事件是否生效
	参数：
		当前回合数
	返回值：
		true为生效
		false为未生效
	*/
	bool Check(int x);
};






//---------------------------------view-------------------------------------

/*
功能：
	参考墨刀原型图打印开始菜单
	实现光标移动选中的文字高亮显示
	在用户按下回车键后可以跳转到相应界面
	跳转入排行榜界面时传入参数0
参数：无
返回值：无
*/
void ShowBeginPage();


/*
功能：
	参考墨刀原型图打印人物选择界面
	实现光标移动选中的文字高亮显示
	首先进行玩家名字输入
	接着进行人物选择
	在光标移动到对应人物上时 人物介绍框刷新出对应人物的背景故事和骰子种类
	按回车键进行选择
	人物选择后进行游戏回合数选择
	选择结束后光标移动到开始游戏上
	按开始游戏后进入游戏界面
参数：无
返回值：无
*/
void ShowCharacterPage();


/*
功能：
	参考墨刀原型图打印游戏界面
	打印地图和角色信息
	将游戏提示信息打印在行动记录框里
	调用游戏运行程序
	跳转至排行榜界面并传入参数1
参数：无
返回值：无
*/
void ShowGamePage();


/*
功能：
	调用Rank()函数获取最近一次排行写入历史文件*dao*
	参考墨刀原型图打印排行榜界面
	若是传入参数为1表示是从游戏界面跳转而来 显示是否再来一局
	选择是跳转至游戏开始界面 选择否结束函数
	若是传入参数为0表示是从开始菜单界面跳转而来 显示返回按钮
	使用返回按钮可以跳转至游戏开始菜单
参数：判断跳转来源
返回值：无
*/
void ShowRankPage();

//--------------------------------service--------------------------------------
/*
功能：
	实现光标移动和文字高亮显示
参数：
	结构体a储存当前光标位置
	结构体b储存目标光标位置
	c表示当前光标指向的文字内容
	d表示目标光标指向的文字内容
返回值：
	无
*/
void MoveCursor(Point a, Point b, std::string c, std::string d);


/*
功能：
	游戏运行
	调用生成星星函数生成一颗星星
	各玩家分别投点 按大小决定回合内行动顺序
	在全局事件队列中加入对应全局事件
	*循环*
	   扫描全局事件队列 将本回合生效的事件弹出并生效
	   扫描当前玩家的事件生效队列和道具生效队列将回合开始时生效的事件和道具弹出并生效
	   判断玩家是否有道具 如有在事件框分别打印出各个道具和跳过选项
	   调用PlayerState();维护玩家状态栏
	   如使用道具 判断道具生效时间 立即生效就立即生效 否则加入玩家的道具生效队列
	   打印提示让玩家按键投点
	   投点结果显示在投点显示框
	   读取点数进行移动
	   每移动一次判断一次是否经过星星或起点
	   如有进行相应判断
	   移动结束判断地图是否有事件
	   如有事件将事件加入事件生效队列
	   将队列中立即生效类型的事件拿出来生效
	   调用Rank();
	   判断是否是本回合最后一个玩家 是就跳出循环 否就继续
	*循环结束*
	局内回合数+1
	判断本局游戏是否结束 否则重复上述循环
	输出胜利提示
	跳转到排行榜界面
	结束函数
参数：无
返回值：无
*/
void GamePlay();


/*
功能：
	生成星星
参数：无
返回值：无
*/
void CreatStar();


/*
功能：
	维护排行榜
	读取全局变量打印排行榜 和当前回合数/总回合数
参数：无
返回值：无
*/
void Rank();


/*
功能：
	维护玩家状态栏
	读取玩家当前状态 打印玩家名称 星星数 骰子种类和数目 道具
参数：无
返回值：无
*/
void PlayerState();

/*
功能：
	在地图上移动
	判断当前是否是岔路
参数：当前地图编号
返回值：无
*/
void MapMove(int x);




class Loot
{
public:
	int loot_time;//道具生效时间
	int loot_id;//道具id
	string loot_name;
	virtual void LootFun(int x);
};

void Loot::LootFun(int x)
{
}
//道具一：偷别人的星星，立即生效
class Loot1:public Loot
{
public:
	Loot1();
	virtual void LootFun(int x);
};

//构造函数
Loot1::Loot1()
{
	//立即生效
	this->loot_time = 1;
	//道具id
	this->loot_id = 1;
	//道具的名字
	this->loot_name = "妙手套白狼";
}

void Loot1::LootFun(int x)
{
	//记录星星数最多的玩家的编号
	int n = 0;
	//记录最多的星星数
	int Max;
	Max = player[0].star_num;
	//查找玩家谁的星星数最多，如果星星一样多，就只能抽取id数小的那一个人的星星了
	for (int i = 1; i <= 9; i++)
	{	
		//如果是自己就跳过
		if (player[i].character_id == x)
		{
			//让自己的星星数+1
			if (Max > 0)
			{
				player[i].star_num += 1;
			}
			continue;
		}
		if (player[i].star_num > Max)
		{
			Max = player[i].star_num;
			n = i;
		}
	}
	//星星数最多的玩家减-1
	if (Max > 0)
	{
		player[n].star_num -= 1;
	}
	
}

//道具二;下次投点，你的点数翻倍,回合开始时生效
class Loot2 :public Loot
{
public:
	Loot2();
	virtual void LootFun(int x);
};

Loot2::Loot2()
{
	//回合开始时生效
	this->loot_time = 2;
	//道具id
	this->loot_id = 2;
	//道具的名字
	this->loot_name = "好事成双";
}

void Loot2::LootFun(int x)
{
	//角色的投点数*2
	character[player[x].character_id]->Roll() *= 2;
}

//道具三：平分星星，立即生效
class Loot3 :public Loot
{
public:
	Loot3();
	virtual void LootFun(int x);
};

Loot3::Loot3()
{
	//立即生效
	this->loot_time = 1;
	//道具id
	this->loot_id = 3;
	//道具的名字
	this->loot_name = "好兄弟不分你我";
}

void Loot3::LootFun(int x)
{
	//指定一名玩家
	printf("请指定一名玩家与他平分星星！");
	int id;
	scanf_s("%d", &id);
	while (id < 0 || id>9)
	{
		printf("没有这名玩家，请重新指定！");
		scanf_s("%d", &id);
	}
	//两位玩家星星数之和
	int num = player[x].star_num + player[id].star_num;
	//二者星星数为偶数，平分星星
	if (num % 2 == 0)
	{
		player[x].star_num = num / 2;
		player[id].star_num = num / 2;
	}
	else
	{
		//不知道玩家有几个，我就当10个来算的

		//创建随机数种子
		srand（(unsigned)time(NULL);
		int num1 = rand() % 10;
		while (num1 == x || num1 == id)
		{
			num1 = rand() % 10;
		}
		//让这个玩家的星星数+1
		player[num1].star_num++;
		num--;
		player[x].star_num = num / 2;
		player[id].star_num = num / 2;
	}
}

//道具四：自己决定星星的位置，回合开始时生效
class Loot4 :public Loot
{
public:
	Loot4();
	virtual void LootFun(int x);
};

Loot4::Loot4()
{
	//立即生效
	this->loot_time = 2;
	//道具id
	this->loot_id = 4;
	//道具的名字
	this->loot_name = "上帝之手";
}

void Loot4::LootFun(int x)
{
	for (int i = 0; i < 87; i++)
	{
		if (mp[i]->star)
		{
			mp[i]->star = false;
		}
	}
	int Num = 0;
	printf("输入地图块编号，星星将会在这个地图块上生成！");
	scanf_s("%d", &Num);
	if (Num < 0 && Num>87)
	{
		printf("没有这个地图块！！");
	}
	//将这个地图块标记为有星星
	mp[Num]->star = true;
	//生成星星
	void CreatStar();
}

//道具五：双倍收益，回合开始时生效
class Loot5 :public Loot
{
public:
	Loot5();
	virtual void LootFun(int x);
};

Loot5::Loot5()
{
	//回合开始时生效
	this->loot_time = 2;
	//道具id
	this->loot_id = 5;
	//道具的名字
	this->loot_name = "双倍收益";
}

void Loot5::LootFun(int x)
{
	//判断玩家位置上有没有星星
	if (mp[player[x]->mp_locat].star)
	{
		//有就给玩家增加一颗星星
		player[x].star_num += 1;
	}
}

//道具六：额外获得一个回合，回合开始时生效
class Loot6 :public Loot
{
public:
	Loot6();
	virtual void LootFun(int x);
};

Loot6::Loot6()
{
	//回合开始时生效
	this->loot_time = 2;
	//道具id
	this->loot_id = 6;
	//道具的名字
	this->loot_name = "年轻人机会多";
}

void Loot6::LootFun(int x)
{
	//这个好像每一个回合是所有玩家一起行动的
	//而这个道具是让这个玩家，单独投点，行动

	//投点
	int count = character[player[x].character_id]->Roll();
	//根据点数在地图上移动
	MapMove(count);
	//回合数+1
	now_round++;
}

//道具七：多走三步，回合开始时生效
class Loot7 :public Loot
{
public:
	Loot7();
	virtual void LootFun(int x);
};

Loot7::Loot7()
{
	//回合开始时生效
	this->loot_time = 2;
	//道具id
	this->loot_id = 7;
	//道具的名字
	this->loot_name = "多走三步";
}

void Loot7::LootFun(int x)
{
	player[x].step += 3;
	player[x].mp_locat += 3;
}
